Merge origin/master into worktree/web-plugin-config

Three seams: the tsconfig path map gained a mapping on each side and keeps
both; the event-producer matrix is generated, so it was regenerated rather
than hand-merged row by row.
This commit is contained in:
Yichen Jiang
2026-08-11 18:27:53 +08:00
1460 changed files with 20030 additions and 19474 deletions
+1 -1
View File
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/web/tool-web/README.md
README.md: 643da4e2f083c2efabd39a462290559ddbd291c8
README.md: 6a7ca42773f4a62b75d6077c5cdd892b0ccfdbee
README.zh.md: 7b52f2b08f393a584258dea1a216d9124ec8760a
+1 -1
View File
@@ -134,5 +134,5 @@ Append-only; newly visible content follows the reusable request prefix and does
## Known Limitations and Deferred Work
- **HTML→markdown conversion degrades on inputs GFM cannot safely represent** — [turndown](https://github.com/mixmark-io/turndown) (with GFM tables/strikethrough) converts at most `fetchMaxOutputChars` source characters through a real DOM. A conservative 512-level lexical guard passes deeply or ambiguously nested bodies through as raw HTML, conversion exceptions do the same, and table `colspan` is ignored because GFM has no spanning-cell representation; these bounds avoid blocking the event loop or expanding output from an untrusted numeric attribute ([archived dependency decision](../../../.agents/notes/archived/simplification/2026-07-26-turndown-for-tool-web-html-markdown.md)).
- **The model-facing surface is minimal by design, with promotions deferred** — `max_results` stays a config bound (not a model argument), and `web_fetch` takes only `url` (no `format`/`prompt`/LLM-summarization mode); both are named later steps in [the seam Agent Note](../../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md).
- **The model-facing API is minimal by design, with promotions deferred** — `max_results` stays a config bound (not a model argument), and `web_fetch` takes only `url` (no `format`/`prompt`/LLM-summarization mode); both are named later steps in [the seam Agent Note](../../../.agents/notes/implemented/architecture/2026-06-24-web-capability-seam.md).
- **No web-specific permission policy** — both tools execute without requesting `ctx.approval`; a deployment that needs confirmation must add a `tools/pre-execute` policy, and the package does not define persistent URL/domain grants.
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/web/web-search-deepseek/README.md
README.md: 1e90f947b4a58288722307aaed50c4889cfe7cb4
README.md: 25162a3e82a05bb17f31a69bc65f6552e42906ad
README.zh.md: 21962bcd390f253f899000be7273a79485821018
+1 -1
View File
@@ -38,7 +38,7 @@ The entry above is the base layer of the `web-search-deepseek` Settings section:
## Mapping
DeepSeek returns no provider-generated answer surface this provider trusts as `content`, so `content` is omitted. `sources[]` comes from `web_search_result` items inside `web_search_tool_result` blocks: `url``url`, `title``title`, and `publishedAt``page_age`. Snippets live separately as URL-keyed `cited_text` entries in a text block's `citations[]`; the provider joins them, leaving `snippet` absent when no excerpt exists.
DeepSeek returns no provider-generated answer content this provider trusts as `content`, so `content` is omitted. `sources[]` comes from `web_search_result` items inside `web_search_tool_result` blocks: `url``url`, `title``title`, and `publishedAt``page_age`. Snippets live separately as URL-keyed `cited_text` entries in a text block's `citations[]`; the provider joins them, leaving `snippet` absent when no excerpt exists.
Results are deduplicated by URL because one request may surface the same page across searches. DeepSeek exposes `maxUses`, not a result-count knob, so the seam enforces `maxResults` by truncating `sources[]` and setting `truncated`.
@@ -27,7 +27,7 @@ import type {
export const DEEPSEEK_PROVIDER_ID = 'deepseek-official'
/**
* Default endpoint: DeepSeek's Anthropic-compatible surface, `/v1` included
* Default endpoint: DeepSeek's Anthropic-compatible API, `/v1` included
* (`/messages` is appended). This is NOT the chat-completions base
* (`https://api.deepseek.com`) `@deepseek-ai/dsh-llm-deepseek` uses, so this
* provider does NOT reuse `$DEEPSEEK_BASE_URL` — only the API key is shared.
@@ -111,7 +111,7 @@ export interface DeepSeekSearchProviderOptions {
/**
* Build a `url → cited_text` map from every `text` block's `citations[]`. This
* is the snippet surface: Anthropic `web_search_result` items carry
* is the snippet source: Anthropic `web_search_result` items carry
* `url`/`title`/`page_age` but typically NO inline snippet — the excerpt lives
* in a separate `text` block's citation, keyed by `url` (first occurrence wins).
*
@@ -14,13 +14,13 @@ export interface WebSearchResultItem {
page_age?: string | null
}
/** A `web_search_tool_result` content block: the citeable result surface. */
/** A `web_search_tool_result` content block: the citeable result shape. */
export interface WebSearchToolResultBlock {
type: 'web_search_tool_result'
content?: WebSearchResultItem[]
}
/** One citation location inside a `text` block (the snippet surface). */
/** One citation location inside a `text` block (the snippet source). */
export interface CitationLocation {
type?: string
url?: string | null
@@ -153,7 +153,7 @@ export class PerplexitySearchProvider implements WebSearchProvider {
}
// These two predicates are intentionally local: exporting generic internals
// from the public web seam would cost more API surface than these pure checks.
// from the public web seam would add more API than these pure checks.
/* jscpd:ignore-start */
/** True for a fetch/`AbortSignal` abort, surfaced as `WEB_ABORTED`. */
function isAbortError(error: unknown): boolean {
@@ -11,7 +11,7 @@ export interface PerplexityRequest {
messages: { role: 'user'; content: string }[]
}
/** One structured search result (the preferred citation surface). */
/** One structured search result (the preferred citation shape). */
export interface PerplexitySearchResult {
url: string
title?: string | null
@@ -22,7 +22,7 @@ export interface PerplexitySearchResult {
/** Perplexity's response envelope. */
export interface PerplexityResponse {
choices?: { message?: { content?: string | null } }[]
/** Structured citation surface (preferred). */
/** Structured citation data (preferred). */
search_results?: PerplexitySearchResult[]
/** URL-only citation fallback. */
citations?: string[]
+1 -1
View File
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/web/web/README.md
README.md: 2acb5022a83c08c33a26be626a93b7355c07a0ed
README.md: 237c7e28416a1f920042d2713a2b2e67dc882c42
README.zh.md: b77b0a897082dba01e10be3f7b0ca3b3f0260a9f
+1 -1
View File
@@ -39,7 +39,7 @@ Selection never depends on registration, config, or HMR order. A capability has
| no id, no usable provider | `WEB_PROVIDER_UNAVAILABLE` |
| no id, multiple usable providers | `WEB_PROVIDER_AMBIGUOUS` |
The failure branches throw `WebError`, whose structured code (plus message detail — the missing id, the ambiguous candidate set) is the surface callers route on. A provider's own `available()` is a cheap local check (credential presence, parseable config) that feeds this execution-time selection and **must not make network calls**; `dsh-tool-web` never calls it — the tool executes through `ctx.web.search()`/`fetch()` and routes on the thrown codes, so provider selection has one owner.
The failure branches throw `WebError`, whose structured code (plus message detail — the missing id, the ambiguous candidate set) is the direct callers route on. A provider's own `available()` is a cheap local check (credential presence, parseable config) that feeds this execution-time selection and **must not make network calls**; `dsh-tool-web` never calls it — the tool executes through `ctx.web.search()`/`fetch()` and routes on the thrown codes, so provider selection has one owner.
## Vocabulary
+1 -1
View File
@@ -28,7 +28,7 @@ export interface WebSearchRequest {
* Normalized search outcome. `content` is optional provider-generated answer
* text or summary (Exa and DeepSeek return none; Perplexity returns a
* generated answer).
* `sources[]` is the portable citation surface. `truncated` is set by the seam
* `sources[]` is the portable citation shape. `truncated` is set by the seam
* when it cut `sources[]` down to `maxResults`.
*/
export interface WebSearchResult {